/**
 * MemberProfileServiceImpl.java
 * 
 * Copyright@2015 OVT Inc. All rights reserved. 
 * 
 * Dec 30, 2015
 */
package com.ovt.doorbell.payment.service;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ovt.doorbell.payment.common.exception.OVTRuntimeException;
import com.ovt.doorbell.payment.common.utils.CollectionUtils;
import com.ovt.doorbell.payment.common.utils.DateTimeUtils;
import com.ovt.doorbell.payment.common.utils.StringUtils;
import com.ovt.doorbell.payment.dao.MemberResourceDao;
import com.ovt.doorbell.payment.dao.constant.MemberResourceStatus;
import com.ovt.doorbell.payment.dao.constant.PurchaseType;
import com.ovt.doorbell.payment.dao.vo.FullMemberProfile;
import com.ovt.doorbell.payment.dao.vo.MemberProfile;
import com.ovt.doorbell.payment.dao.vo.MemberResource;
import com.ovt.doorbell.payment.dao.vo.Resource;
import com.ovt.doorbell.payment.service.constant.DoorbellConstants;
import com.ovt.doorbell.payment.service.exception.ServiceErrorCode;
import com.ovt.doorbell.payment.service.exception.ServiceException;
import com.ovt.order.util.entity.OrderState;
import com.ovt.order.util.entity.RefundRequest;

/**
 * MemberProfileServiceImpl
 * 
 * @Author zhi.liu
 * @Version 1.0
 * @See
 * @Since [OVT Cloud Platform]/[API] 1.0
 */
@Service
public class MemberProfileServiceImpl implements MemberProfileService
{
    @Autowired
    private ResourceService resourceService;

    @Autowired
    private PriceService priceService;

    @Autowired
    private RefundService refundService;

    @Autowired
    private MemberResourceDao memberResourceDao;

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#getMemberProfile
     * (long)
     */
    @Override
    public MemberProfile getMemberProfile(String userId)
            throws ServiceException
    {
        MemberProfile memberProfile = memberResourceDao
                .getMemberResource(userId);

        // load default resource
        this.loadDefaultResource(userId, memberProfile);

        return memberProfile;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#getFullMemberProfile
     * (java.lang.String)
     */
    @Override
    public FullMemberProfile getFullMemberProfile(String userId)
            throws ServiceException
    {

        return null;
    }

    /**
     * Load default resource if user didn't buy such type resource.
     * 
     * @param userId
     * @param memberProfile
     * @throws ServiceException
     */
    private void loadDefaultResource(String userId, MemberProfile memberProfile)
            throws ServiceException
    {
        List<Resource> defaultResources = resourceService.getDefaultResource();

        for (Resource resource : defaultResources)
        {
            if (memberProfile == null)
            {
                memberProfile = new MemberProfile();
                memberProfile.setUserId(userId);
            }

            MemberResource memberResource = memberProfile.getResource(resource
                    .getType());
            if (memberResource == null)
            {
                MemberResource defResource = new MemberResource();
                defResource.setResourceType(resource.getType());
                defResource.setResourceSize(resource.getSize());
                defResource.setStatus(MemberResourceStatus.ACTIVE);

                memberProfile.getResources().add(defResource);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#getPurchaseType
     * (com.ovt.doorbell.payment.dao.vo.MemberProfile)
     */
    @Override
    public PurchaseType getPurchaseType(MemberProfile memberProfile)
            throws ServiceException
    {
        PurchaseType purchaseType = PurchaseType.PURCHASE;

        if (memberProfile != null
                && CollectionUtils.isNotEmpty(memberProfile.getResources()))
        {
            boolean isDefault = true;
            boolean willExpire = true; // will expire in 30 days
            for (MemberResource memberResource : memberProfile.getResources())
            {
                isDefault &= resourceService.isDefaultResource(
                        memberResource.getResourceType(),
                        memberResource.getResourceSize());

                willExpire &= DateTimeUtils.addDays(
                        DateTimeUtils.getCurrentTimestamp(),
                        DoorbellConstants.DAYS_OF_MONTH).after(
                        memberResource.getExpireTime());
            }

            // 1. PURCHASE: all are default resources
            if (isDefault)
            {
                purchaseType = PurchaseType.PURCHASE;
            }
            else
            {
                // 2. RENEW: all will expire in 30 days
                if (willExpire)
                {
                    purchaseType = PurchaseType.RENEW;
                }
                else
                {
                    // 3. UPGRADE: except case #1, #2
                    purchaseType = PurchaseType.UPGRADE;
                }
            }

        }

        return purchaseType;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#saveProfile(com
     * .ovt.doorbell.payment.dao.vo.MemberProfile,
     * com.ovt.doorbell.payment.dao.constant.PurchaseType)
     */
    @Override
    public void saveProfile(MemberProfile memberProfile,
            PurchaseType purchaseType) throws ServiceException
    {
        List<MemberResource> newMemberResources = new ArrayList<MemberResource>();
        List<MemberResource> updatedMemberResources = new ArrayList<MemberResource>();

        List<MemberResource> resources = memberProfile.getResources();
        for (MemberResource memberResource : resources)
        {
            if (purchaseType == PurchaseType.PURCHASE)
            {
                if (!resourceService.isDefaultResource(
                        memberResource.getResourceType(),
                        memberResource.getResourceSize()))
                {
                    newMemberResources.add(memberResource);
                }
            }
            else if (purchaseType == PurchaseType.RENEW)
            {
                if (!resourceService.isDefaultResource(
                        memberResource.getResourceType(),
                        memberResource.getResourceSize())
                        && memberResource.getStatus() != MemberResourceStatus.ACTIVE)
                {
                    newMemberResources.add(memberResource);
                }
            }
            else if (purchaseType == PurchaseType.UPGRADE)
            {
                if (!resourceService.isDefaultResource(
                        memberResource.getResourceType(),
                        memberResource.getResourceSize()))
                {
                    if (memberResource.getEndTime() != null)
                    {
                        updatedMemberResources.add(memberResource);
                    }
                    else
                    {
                        newMemberResources.add(memberResource);
                    }
                }
            }
        }

        try
        {
            memberResourceDao.save(memberProfile.getUserId(),
                    newMemberResources.toArray(new MemberResource[0]));
            memberResourceDao.update(updatedMemberResources
                    .toArray(new MemberResource[0]));
        }
        catch (OVTRuntimeException e)
        {
            String errMsg = MessageFormat.format(
                    "Failed to persistent member profile of user [{}]!",
                    memberProfile.getUserId());
            throw new ServiceException(
                    ServiceErrorCode.PROFILE_PERSISTENT_FAIL, errMsg);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#preCancelProfile
     * (java.lang.String)
     */
    @Override
    public FullMemberProfile preCancelProfile(String userId)
            throws ServiceException
    {
        FullMemberProfile fullMemberProfile = this.getFullMemberProfile(userId);

        // 1. check expire time, must not in 30 days.
        this.checkExpireTime(fullMemberProfile);

        // 2. calculate refund fee.
        priceService.calculateRefundFee(fullMemberProfile);

        return fullMemberProfile;

    }

    private void checkExpireTime(FullMemberProfile fullMemberProfile)
            throws ServiceException
    {
        Date expireDate = DateTimeUtils.parseDate(
                fullMemberProfile.getExpireTime(),
                DateTimeUtils.PATTERN_SQL_DATETIME_FULL);
        Date cancelDeadline = DateTimeUtils.addDays(expireDate,
                -DoorbellConstants.DAYS_OF_MONTH);
        Date current = new Date();

        if (current.after(cancelDeadline))
        {
            throw new ServiceException(ServiceErrorCode.CANNOT_CANCEL,
                    "Profile will expire in 30 days!");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.MemberProfileService#cancelProfile(java
     * .lang.String)
     */
    @Override
    public long cancelProfile(String userId) throws ServiceException
    {
        // 1. get member profile
        MemberProfile memberProfile = this.getMemberProfile(userId);
        FullMemberProfile fullMemberProfile = this.getFullMemberProfile(userId);

        List<String> orderNos = this.getOrderNos(memberProfile);

        // 2. create refund requests
        List<RefundRequest> refundRequests = new ArrayList<RefundRequest>();
        List<MemberResource> memberResources = memberProfile.getResources();
        for (MemberResource memberResource : memberResources)
        {

            RefundRequest refundRequest = new RefundRequest();
            refundRequest.setOrderNo(memberResource.getOrderNo());
            refundRequest.setRefundFee(this.getRefundFee(fullMemberProfile));
            refundRequest.setRefundReasonId();
            refundRequest.setRefundDesc(this.getRefundDesc(memberResource));

            refundRequests.add(refundRequest);

            // refundService.applyRefund(refundRequest);
        }

        this.mergeRefundRequestOfSameOrder(refundRequests);

        return 0;
    }

    /**
     * @param memberResource
     * @return
     */
    private String getRefundDesc(MemberResource memberResource)
    {
        String desc = "Cancel: " + memberResource.getResourceType() + "-"
                + memberResource.getResourceSize() + StringUtils.NEW_LINE;
        return desc;
    }

    /**
     * @param memberResource
     * @return
     * @throws ServiceException
     */
    private float getRefundFee(FullMemberProfile fullMemberProfile)
            throws ServiceException
    {
        priceService.calculateRefundFee(fullMemberProfile);
        return 0;
    }

    /**
     * @param memberProfile
     * @return
     */
    private List<String> getOrderNos(MemberProfile memberProfile)
    {
        // TODO Auto-generated method stub
        return null;
    }

}
